package com.piece.flowable.controller;

import com.piece.core.framework.annotation.permission.AclPermission;
import com.piece.core.framework.annotation.permission.SubmitPermission;
import com.piece.core.framework.exception.ServerException;
import com.piece.core.framework.support.bootstrap.DataTable;
import com.piece.core.framework.support.bootstrap.QueryTable;
import com.piece.core.framework.support.dto.UserDetailDTO;
import com.piece.core.framework.support.response.AjaxResponse;
import com.piece.core.framework.util.basic.I18nUtil;
import com.piece.core.framework.util.file.FileUtil;
import com.piece.core.framework.util.string.JsonUtil;
import com.piece.core.framework.util.string.StringUtil;
import com.piece.core.log.config.UserContextHolder;
import com.piece.core.web.controller.FrameWorkController;
import com.piece.module.flowable.constants.ExceptionConstants;
import com.piece.module.flowable.dto.WfNextNode;
import com.piece.module.flowable.dto.WfTask;
import com.piece.module.flowable.service.WfCopyService;
import com.piece.module.flowable.service.WfTaskService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@RestController
@Api(tags = {"流程任务管理"})
@RequestMapping("/api/workflow/task")
public class WfTaskController extends FrameWorkController {

    @Resource
    private WfTaskService wfTaskService;

    @Resource
    private WfCopyService wfCopyService;

    @PostMapping("/ownTable")
    @AclPermission
    @ApiOperation(value = "查询我的流程分页数据")
    @ApiImplicitParam(value = "查询条件", dataTypeClass = QueryTable.class, type = "body")
    public AjaxResponse ownTable() {
        QueryTable queryTable = initTable();
        queryTable.getParams().put("starter", UserContextHolder.getUserId());
        DataTable dataTable = wfTaskService.findPage(queryTable);
        return success(dataTable);
    }

    @PostMapping("/claimTable")
    @AclPermission
    @ApiOperation(value = "查询待签列表分页数据")
    @ApiImplicitParam(value = "查询条件", dataTypeClass = QueryTable.class, type = "body")
    public AjaxResponse claimTable() {
        QueryTable queryTable = initTable();
        DataTable dataTable = wfTaskService.findClaimPage(queryTable);
        return success(dataTable);
    }

    @PostMapping("/copyTable")
    @AclPermission
    @ApiOperation(value = "查询抄送列表分页数据")
    @ApiImplicitParam(value = "查询条件", dataTypeClass = QueryTable.class, type = "body")
    public AjaxResponse copyTable() {
        QueryTable queryTable = initTable();
        DataTable dataTable = wfCopyService.findPage(queryTable);
        return success(dataTable);
    }

    @PostMapping("/finishedTable")
    @AclPermission
    @ApiOperation(value = "查询完成列表分页数据")
    @ApiImplicitParam(value = "查询条件", dataTypeClass = QueryTable.class, type = "body")
    public AjaxResponse finishedList() {
        QueryTable queryTable = initTable();
        DataTable dataTable = wfTaskService.findFinishedPage(queryTable);
        return success(dataTable);
    }

    @PostMapping("/todoTable")
    @AclPermission
    @ApiOperation(value = "查询待办列表分页数据")
    @ApiImplicitParam(value = "查询条件", dataTypeClass = QueryTable.class, type = "body")
    public AjaxResponse todoTable() {
        QueryTable queryTable = initTable();
        DataTable dataTable = wfTaskService.findTodoPage(queryTable);
        return success(dataTable);
    }

    @PostMapping("/todoCount")
    @ApiOperation(value = "查询代办任务数量")
    public AjaxResponse todoCount(UserDetailDTO user) {
        return success(wfTaskService.countTodoProcess(user.getId()));
    }

    @GetMapping("/formData")
    @ApiOperation(value = "加载流程关联表单")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "definitionId", value="流程定义id"),
            @ApiImplicitParam(name = "deployId", value="流程部署id")
    })
    public AjaxResponse formData() {
        String definitionId = getRequest().getParameter("definitionId");
        String deployId = getRequest().getParameter("deployId");
        String formContent = wfTaskService.getFormContent(definitionId, deployId);
        return success(JsonUtil.toMap(formContent));
    }

    @GetMapping("/processDetailData")
    @ApiOperation(value = "查询流程定义关联数据")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "procInsId", value="流程定义id"),
            @ApiImplicitParam(name = "deployId", value="流程部署id"),
            @ApiImplicitParam(name = "taskId", value="流程任务id")
    })
    public AjaxResponse processDetailData() {
        String procInsId = getRequest().getParameter("procInsId");
        String deployId = getRequest().getParameter("deployId");
        String taskId = getRequest().getParameter("taskId");
        return success(wfTaskService.queryProcessDetail(procInsId, deployId, taskId));
    }

    @GetMapping("/nextFlowNode")
    @ApiOperation(value = "获取下一节点")
    @ApiImplicitParams({
            @ApiImplicitParam(name="taskId", value = "流程任务Id"),
            @ApiImplicitParam(name="deployId", value = "流程部署id")
    })
    public AjaxResponse nextFlowNode() {
        String deployId = getRequest().getParameter("deployId");
        String taskId = getRequest().getParameter("taskId");
        WfNextNode nextFlowNode = wfTaskService.getNextFlowNode(deployId, taskId);
        return null == nextFlowNode ? success("流程已结束") : success(nextFlowNode);
    }

    @RequestMapping("/flowViewer/{procInsId}")
    @ApiOperation(value = "获取流程执行节点")
    @ApiImplicitParam(name="procInsId", value = "流程实例Id", type = "path")
    public AjaxResponse flowViewer(@PathVariable String procInsId) {
        return success(wfTaskService.getFlowViewer(procInsId));
    }

    @PostMapping("/start/{processDefId}")
    @AclPermission(code = "flowable:process:active")
    @ApiOperation(value = "根据流程定义id启动流程实例")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "processDefId", value="流程定义id", type = "path"),
            @ApiImplicitParam(name = "variables", value="变量集合", dataTypeClass = Map.class)
    })
    public AjaxResponse start(@PathVariable String processDefId) {
        Map<String, Object> variables = new HashMap<>();
        initMap(variables);
        try {
            wfTaskService.startTask(processDefId, null, variables);
            return success();
        } catch (Exception e) {
            return error(e.getMessage());
        }
    }

    @SubmitPermission
    @PostMapping("/complete")
    @ApiOperation(value = "审批任务")
    @ApiImplicitParam(name="wfTask", value = "流程任务", dataTypeClass = WfTask.class)
    public AjaxResponse complete() {
        WfTask wfTask = new WfTask();
        initDB(wfTask);
        try {
            wfTaskService.completeTask(wfTask);
            return success();
        } catch (Exception e) {
            return error(e.getMessage());
        }
    }

    @SubmitPermission
    @PostMapping("/reject")
    @ApiOperation(value = "驳回任务")
    @ApiImplicitParam(name="wfTask", value = "流程任务", dataTypeClass = WfTask.class)
    public AjaxResponse reject() {
        WfTask wfTask = new WfTask();
        initDB(wfTask);
        try {
            wfTaskService.rejectTask(wfTask);
            return success();
        } catch (Exception e) {
            return error(e.getMessage());
        }
    }

    @SubmitPermission
    @PostMapping("/rollback")
    @AclPermission(code = "flowable:task:rollback")
    @ApiOperation(value = "回退任务")
    @ApiImplicitParam(name="wfTask", value = "流程任务", dataTypeClass = WfTask.class)
    public AjaxResponse rollback() {
        WfTask wfTask = new WfTask();
        initDB(wfTask);
        try {
            wfTaskService.rollbackTask(wfTask);
            return success();
        } catch (Exception e) {
            return error(e.getMessage());
        }
    }

    @PostMapping("/rollback/list")
    @ApiOperation(value = "获取所有可回退的节点")
    @ApiImplicitParams({
            @ApiImplicitParam(name="taskId", value = "流程任务Id"),
            @ApiImplicitParam(name="taskName", value = "流程任务名称")
    })
    public AjaxResponse variables() {
        String taskId = getRequest().getParameter("taskId");
        String taskName = getRequest().getParameter("taskName");
        return success(wfTaskService.findRollbackTaskList(taskId, taskName));
    }

    @SubmitPermission
    @PostMapping("/claim")
    @AclPermission(code = "flowable:task:claim")
    @ApiOperation(value = "认领/签收任务")
    @ApiImplicitParam(name="wfTask", value = "流程任务", dataTypeClass = WfTask.class)
    public AjaxResponse claim() {
        WfTask wfTask = new WfTask();
        initDB(wfTask);
        try {
            wfTaskService.claimTask(wfTask);
            return success();
        } catch (Exception e) {
            return error(e.getMessage());
        }
    }

    @SubmitPermission
    @PostMapping("/unClaim")
    @AclPermission(code = "flowable:task:claim")
    @ApiOperation(value = "取消认领/签收任务")
    @ApiImplicitParam(name="wfTask", value = "流程任务", dataTypeClass = WfTask.class)
    public AjaxResponse unClaim() {
        WfTask wfTask = new WfTask();
        initDB(wfTask);
        try {
            wfTaskService.unClaimTask(wfTask);
            return success();
        } catch (Exception e) {
            return error(e.getMessage());
        }
    }

    @SubmitPermission
    @PostMapping("/delegate")
    @ApiOperation(value = "委派任务")
    @ApiImplicitParam(name="wfTask", value = "流程任务", dataTypeClass = WfTask.class)
    public AjaxResponse delegate() {
        WfTask wfTask = new WfTask();
        initDB(wfTask);
        if (StringUtil.isEmpty(wfTask.getTaskId())) {
            return error(I18nUtil.message(ExceptionConstants.NOT_EXIST, "任务主键"));
        }
        if (null == wfTask.getClaimUser()) {
            return error(I18nUtil.message(ExceptionConstants.NOT_EXIST, "委派人"));
        }
        try {
            wfTaskService.delegateTask(wfTask);
            return success();
        } catch (Exception e) {
            return error(e.getMessage());
        }
    }

    @SubmitPermission
    @PostMapping("/transfer")
    @ApiOperation(value = "转办任务")
    @ApiImplicitParam(name="wfTask", value = "流程任务", dataTypeClass = WfTask.class)
    public AjaxResponse transfer() {
        WfTask wfTask = new WfTask();
        initDB(wfTask);
        if (StringUtil.isEmpty(wfTask.getTaskId())) {
            return error(I18nUtil.message(ExceptionConstants.NOT_EXIST, "任务主键"));
        }
        if (null == wfTask.getClaimUser()) {
            return error(I18nUtil.message(ExceptionConstants.NOT_EXIST, "转办人"));
        }
        try {
            wfTaskService.delegateTask(wfTask);
            return success();
        } catch (Exception e) {
            return error(e.getMessage());
        }
    }

    @SubmitPermission
    @PostMapping("/cancel")
    @ApiOperation(value = "取消申请")
    @ApiImplicitParam(name="wfTask", value = "流程任务", dataTypeClass = WfTask.class)
    public AjaxResponse cancel() {
        WfTask wfTask = new WfTask();
        initDB(wfTask);
        try {
            wfTaskService.cancelTask(wfTask);
            return success();
        } catch (Exception e) {
            return error(e.getMessage());
        }
    }

    @Deprecated
    @SubmitPermission
    @PostMapping("/revoke")
    @AclPermission(code = "flowable:task:revoke")
    @ApiOperation(value = "撤回流程")
    @ApiImplicitParam(name="wfTask", value = "流程任务", dataTypeClass = WfTask.class)
    public AjaxResponse revoke() {
        WfTask wfTask = new WfTask();
        initDB(wfTask);
        try {
            wfTaskService.rejectTask(wfTask);
            return success();
        } catch (Exception e) {
            return error(e.getMessage());
        }
    }

    @SubmitPermission
    @PostMapping("/delete")
    @AclPermission(code = "flowable:task:delete")
    @ApiOperation(value = "删除任务")
    @ApiImplicitParams({
            @ApiImplicitParam(name="taskId", value = "流程任务ID"),
            @ApiImplicitParam(name="reason", value = "删除原因")
    })
    public AjaxResponse delete() {
        String ids = getRequest().getParameter("taskIds");
        String reason = getRequest().getParameter("reason");
        try {
            String[] taskIds = ids.split(",");
            Arrays.stream(ids.split(",")).forEach(taskId -> {
                wfTaskService.deleteTask(taskId, reason);
            });

            return success(I18nUtil.message(com.piece.core.framework.constant.ExceptionConstants.DELETE_SUCCESS), null);
        } catch (Exception e) {
            return error(I18nUtil.message(com.piece.core.framework.constant.ExceptionConstants.DELETE_FAILURE), e.getMessage());
        }
    }

    @SubmitPermission
    @PostMapping("/instance/delete")
    @ApiOperation(value = "删除流程实例")
    @ApiImplicitParams({
            @ApiImplicitParam(name="instanceId", value = "流程实例ID"),
            @ApiImplicitParam(name="reason", value = "删除原因")
    })
    public AjaxResponse deleteInstance() {
        String instanceId = getRequest().getParameter("instanceId");
        String reason = getRequest().getParameter("reason");
        try {
            wfTaskService.deleteInstance(instanceId, reason);
            return success(I18nUtil.message(com.piece.core.framework.constant.ExceptionConstants.DELETE_SUCCESS), null);
        } catch (Exception e) {
            return error(I18nUtil.message(com.piece.core.framework.constant.ExceptionConstants.DELETE_FAILURE), e.getMessage());
        }
    }

    @GetMapping("/variables/{taskId}")
    @ApiOperation(value = "获取流程变量")
    @ApiImplicitParam(name="taskId", value = "流程任务Id", type = "path")
    public AjaxResponse variables(@PathVariable String taskId) {
        return success(wfTaskService.getProcessVariables(taskId));
    }

    @RequestMapping("/diagram/{processId}")
    @ApiOperation(value = "生成流程图")
    @ApiImplicitParam(name="processId", value = "任务ID", type = "path")
    public void genProcessDiagram(@PathVariable String processId) {
        try {
            InputStream inputStream = wfTaskService.diagram(processId);
            FileUtil.imageForWeb(getRequest(), getResponse(), inputStream, "流程图.png");
        } catch (Exception e) {
            throw new ServerException(e.getMessage());
        }
    }
}
